package me.zhengjie.domain;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateTime;
import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.dto.FindInventoryParameter;
import me.zhengjie.dto.StorageMsg;
import me.zhengjie.dto.sqlServer.*;
import me.zhengjie.dto.OutBoundParameter;
import me.zhengjie.repository.*;
import me.zhengjie.service.StorageService;
import me.zhengjie.util.LoginUtil;
import me.zhengjie.util.UniqueCodeUtil;
import me.zhengjie.wcs.WcsStatus;
import me.zhengjie.wcs.WmsToWcs;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import java.util.UUID;

import java.sql.Timestamp;
import java.util.*;
import java.util.stream.Collectors;

@Slf4j
@Component
@RequiredArgsConstructor
public class OutBoundService {

    private final StorageRepository storageRepository;
    private final InventoryRepository inventoryRepository;
    private final OutBoundOrderRepository outBoundOrderRepository;
    private final OutBoundOrderDetailRepository outBoundOrderDetailRepository;
    private final OutBoundMissionRepository outBoundMissionRepository;
    private final PalletRepository palletRepository;
    private final StorageService storageService;
    private final WcsStatus wcsStatus;
    private final WmsTaskRepository wmsTaskRepository;
    private final WmsToWcs wmsToWcs;
    private final ProcesscardRepository processcardRepository;

    /**
     * 根据提供的工程号，载盘码，数量等信息确定需要出库的库存
     * @param parameter 出库任务参数
     * @return 出库任务集合
     */
    public List<Inventory> getInventory(OutBoundParameter parameter){
        Timestamp timestamp = DateTime.now().toTimestamp();
        switch (parameter.getParameterType()){
            // 输入工程号和数量自动匹配库存
            case 1:
                String workNum = parameter.getWorkNum();
                int qty = parameter.getQty();

                // 获取所有的指定库区的储位,转化为List<Integer> storageIds
                List<Integer> storageIds = storageRepository.findStoragesByZoneCode(parameter.getZoneCode())
                        .stream()
                        .map(Storage::getId)
                        .collect(Collectors.toList());

                String processcardCode = parameter.getProcesscardCode();

                if (processcardCode.startsWith("-")) {
                    processcardCode = "  ".concat(processcardCode);
                }
//                else {
//                    int index = processcardCode.indexOf("-");
//                    String afterCut = processcardCode.substring(index);
//                    processcardCode = "  ".concat(afterCut);
//                }
                Processcard processcard = processcardRepository.findByProcesscardCode(processcardCode);

                // 该库区的所有库存
                List<Inventory> inventories = inventoryRepository.findInventoriesInStorageId(workNum, processcard.getId(), storageIds);

                // 匹配寻求库存
                return inventories.stream()
                        .filter(i -> i.getInventoryStatus()==1)
                        .sorted(Comparator.comparing(Inventory::getInBoundFinishTime))
                        .collect(Collectors.toList())
                        .subList(0,qty);

                /*return inventoryRepository.findInventoriesByWorkNumAndInventoryStatusAndInBoundFinishTimeBeforeOrderByInBoundFinishTime(workNum, 1, timestamp)
                        .subList(0,qty);*/

            // 选择库位出库
            case 2:
                int storageId = parameter.getStorageId();
                Inventory inventory = inventoryRepository.findInventoryByStorageId(storageId);
                storageService.lockStorage(storageId);
                return Collections.singletonList(inventory);
        }
        return null;
    }

    /**
     * 根据查询条件查找对应的库存
     * @param workNum 工程号
     * @param zoneCode 库区
     * @param processcardCode 批次号
     * @return 库存列表
     */
    public List<Inventory> findInventoryByWorkNumAndZoneCode(String workNum,String zoneCode, String processcardCode){
        List<Integer> storageIds = storageRepository.findStoragesByZoneCode(zoneCode)
                .stream()
                .map(Storage::getId)
                .collect(Collectors.toList());

        /*// 查找批次号信息
        if (processcardCode.startsWith("-")) {
            processcardCode = "  ".concat(processcardCode);
        }else {
            int index = processcardCode.indexOf("-");
            String afterCut = processcardCode.substring(index);
            processcardCode = "  ".concat(afterCut);
        }*/


        Processcard processcard = processcardRepository.findByProcesscardCode(processcardCode);
        if (ObjectUtil.isEmpty(processcard)){
            return Collections.emptyList();
        }
        // 该库区的所有库存
        return inventoryRepository.findInventoriesInStorageId(workNum, processcard.getId(), storageIds);
    }

    /**
     *  保存出库单
     * @param parameter 出库任务参数
     */
    public OutBoundOrder saveOutBoundOrder(OutBoundParameter parameter){
        List<Inventory> inventories = getInventory(parameter);

        // 锁储位
        List<Integer> storageIds = inventories.stream().map(Inventory::getStorageId).collect(Collectors.toList());
        for (Integer storageId : storageIds ){
            storageService.lockStorage(storageId);
        }
        // 更改库存状态
        inventories.stream()
                .peek(x -> x.setInventoryStatus(2))
                .forEach(inventoryRepository::save);
        if (parameter.getParameterType()==1){
            OutBoundOrder outBoundOrderAuto = new OutBoundOrder();
            outBoundOrderAuto.setOrderCode(UniqueCodeUtil.createCode());
            outBoundOrderAuto.setOrderType(1);
            outBoundOrderAuto.setOrderStatus(0);
            outBoundOrderAuto.setWorkNum(inventories.get(0).getWorkNum());
            outBoundOrderAuto.setPriority(0);
            outBoundOrderAuto.setCreateTime(DateTime.now().toTimestamp());
            outBoundOrderAuto.setCreateBy(LoginUtil.getLoginUser());
            outBoundOrderRepository.save(outBoundOrderAuto);
            return outBoundOrderAuto;
        }else if (parameter.getParameterType()==2){
            OutBoundOrder outBoundOrderManual = new OutBoundOrder();
            outBoundOrderManual.setOrderCode(UniqueCodeUtil.createCode());
            outBoundOrderManual.setOrderType(2);
            outBoundOrderManual.setOrderStatus(0);
            outBoundOrderManual.setWorkNum(inventories.get(0).getWorkNum());
            outBoundOrderManual.setPriority(1);
            outBoundOrderManual.setCreateTime(DateTime.now().toTimestamp());
            outBoundOrderManual.setCreateBy(LoginUtil.getLoginUser());
            outBoundOrderRepository.save(outBoundOrderManual);
            return outBoundOrderManual;
        }
        return null;
    }

    /**
     * 创建出库订单明细
     * @param inventories 出库任务参数
     * @return 出库订单明细集合
     */
    public List<OutBoundOrderDetail> createOrderDetail(List<Inventory> inventories){
         return inventories.stream().map(x -> {
             // 保存订单明细
            OutBoundOrderDetail outBoundOrderDetail = new OutBoundOrderDetail();
            List<OutBoundOrder> outBoundOrders = outBoundOrderRepository.findAll();
             OutBoundOrder outBoundOrder = outBoundOrders.stream().sorted(Comparator.comparing(OutBoundOrder::getCreateTime).reversed()).limit(1).collect(Collectors.toList()).get(0);
             outBoundOrderDetail.setOutBoundOrderId(outBoundOrder.getId());
            outBoundOrderDetail.setPalletId(x.getPalletId());
            outBoundOrderDetailRepository.save(outBoundOrderDetail);
            return outBoundOrderDetail;
        }).collect(Collectors.toList());
         // 生成出库任务

    }

    /**
     * 根据订单明细生成出库任务
     * @param outBoundOrderDetails 出库请求参数
     * @return
     */
    public List<OutBoundMission> createOutBoundMission(List<OutBoundOrderDetail> outBoundOrderDetails){
        List<OutBoundMission> outBoundMissions = new ArrayList<>();
        for (OutBoundOrderDetail x : outBoundOrderDetails) {
            OutBoundMission outBoundMission = new OutBoundMission();
            outBoundMission.setMissionCode(UniqueCodeUtil.createCode());
            outBoundMission.setOutBoundOrderId(x.getOutBoundOrderId());
            outBoundMission.setPriority(outBoundOrderRepository.findPriorityById(x.getOutBoundOrderId()));
            outBoundMission.setMissionStatus(0);
            outBoundMission.setPalletCode(palletRepository.findPalletCodeById(x.getPalletId()));

            // 查找储位
            String storageCode = storageService.findStorageCodeById(inventoryRepository.findStorageIdByPalletId(x.getPalletId()));
            outBoundMission.setSource(storageCode);

            // 设置终点
            outBoundMission.setDestination("AOutBound");

            outBoundMission.setCreateTime(DateTime.now().toTimestamp());
            log.info("出库单id:{}",x.getOutBoundOrderId());
            log.info("创建的出库任务：{}",outBoundMission);

            // 休眠1毫秒
            try {
                Thread.sleep(200);
            } catch (InterruptedException e) {
                log.error("批量生成出库任务时休眠1毫秒出错");
            }
            outBoundMissions.add(outBoundMission);
        }
        /*List<OutBoundMission> outBoundMissions = outBoundOrderDetails.stream().map(x -> {
            OutBoundMission outBoundMission = new OutBoundMission();
            outBoundMission.setMissionCode(UniqueCodeUtil.createCode());
            outBoundMission.setOutBoundOrderId(x.getOutBoundOrderId());
            outBoundMission.setPriority(outBoundOrderRepository.findPriorityById(x.getOutBoundOrderId()));
            outBoundMission.setMissionStatus(0);
            outBoundMission.setPalletCode(palletRepository.findPalletCodeById(x.getPalletId()));

            // 查找储位
            String storageCode = storageService.findStorageCodeById(inventoryRepository.findStorageIdByPalletId(x.getPalletId()));
            outBoundMission.setSource(storageCode);

            // 设置终点
            outBoundMission.setDestination("AOutBound");

            outBoundMission.setCreateTime(DateTime.now().toTimestamp());

            // 休眠1毫秒
            try {
                Thread.sleep(1);
            } catch (InterruptedException e) {
                log.error("批量生成出库任务时休眠1毫秒出错");
            }
            return outBoundMission;
        }).collect(Collectors.toList());
        outBoundMissionRepository.saveAll(outBoundMissions);*/
        outBoundMissionRepository.saveAll(outBoundMissions);
        return outBoundMissions;
    }

    /**
     * 向wcs发送出库任务
     * @param outBoundMissions 出库任务列表
     */
    public void createOutTask(List<OutBoundMission> outBoundMissions){
        List<WmsTask> wmsTaskList = outBoundMissions.stream().map(x -> {
            WmsTask wmsTask = new WmsTask();
            wmsTask.setLogicalAddressType(1);
            wmsTask.setWmsTaskId(x.getMissionCode());
            wmsTask.setLpnCode(x.getPalletCode());
            wmsTask.setLpnType(1);
            wmsTask.setWcsTaskType(2);
            wmsTask.setAisle(1);
            wmsTask.setFromLocation(x.getSource());
            wmsTask.setToLocation(x.getDestination());
            wmsTask.setLevel(x.getPriority());
            wmsTask.setStatus(x.getMissionStatus());
            wmsTask.setCreated(x.getCreateTime());
            return wmsTask;
        }).collect(Collectors.toList());
        log.info("生成的wmsTask任务列表：{}",wmsTaskList);
        // 将出库任务保存到wms_task就是下发任务，定时器从wms_task表中按创建时间取任务发给wcs
        wmsTaskRepository.saveAllAndFlush(wmsTaskList);
    }

    /**
     * 查找所有的出库单
     * @return
     */
    public List<OutBoundOrder> findAllOrder(){
        return outBoundOrderRepository.findAllOrderByCreateTime();
    }

    @Transactional
    public void deleteOutBoundMissionById(Integer id){
        outBoundMissionRepository.deleteById(id);
    }

    public List<StorageMsg> getStorageMsg(List<Storage> storages){
        return storages.stream().map(x ->{
            StorageMsg storageMsg = new StorageMsg();
            if (x.getLocationInventoryStatus()==0){
                storageMsg.setStorageId(x.getId());
                storageMsg.setStorageCode(x.getStorageCode());
                storageMsg.setZoneCode(x.getZoneCode());
                storageMsg.setAisle(x.getAisle());
                storageMsg.setLayer(x.getLayer());
                storageMsg.setRow(x.getRow());
                storageMsg.setColumn(x.getColumn());
                storageMsg.setLocationInventoryStatus(x.getLocationInventoryStatus());
                storageMsg.setStatus(x.getStatus());
                return storageMsg;
            }
            Pallet pallet = palletRepository.findPalletById(x.getPalletId());
            if (ObjectUtil.isEmpty(pallet)){
                log.error("储位载盘信息丢失！！！，储位号：{}",x.getStorageCode());
            }
            Processcard processcard = processcardRepository.findProcesscardById(pallet.getProcesscardId());
            if (ObjectUtil.isEmpty(processcard)){
                log.error("储位载盘的工艺卡信息丢失！！！，储位号：{}",x.getStorageCode());
            }
            storageMsg.setStorageId(x.getId());
            storageMsg.setStorageCode(x.getStorageCode());
            storageMsg.setPalletId(pallet.getPalletCode());
            storageMsg.setProcesscardCode(processcard.getProcesscardCode());
            storageMsg.setWorkNum(processcard.getWorkNum());
            storageMsg.setProductType(processcard.getProductType());
            storageMsg.setMaterial(processcard.getMaterial());
            storageMsg.setThick(processcard.getThick());
            storageMsg.setSize1(processcard.getSize1());
            storageMsg.setSize2(processcard.getSize2());
            storageMsg.setQty(processcard.getQty());
            storageMsg.setLayerName(processcard.getLayerName());
            storageMsg.setZoneCode(x.getZoneCode());
            storageMsg.setAisle(x.getAisle());
            storageMsg.setLayer(x.getLayer());
            storageMsg.setRow(x.getRow());
            storageMsg.setColumn(x.getColumn());
            storageMsg.setLocationInventoryStatus(x.getLocationInventoryStatus());
            storageMsg.setStatus(x.getStatus());
            return storageMsg;
        }).collect(Collectors.toList());
    }

    public List<String> getAllWorkNum(){
        try {
            return processcardRepository
                    .findAll()
                    .stream()
                    .map(Processcard::getWorkNum)
                    .distinct()
                    .collect(Collectors.toList());
        } catch (Exception e) {
            return null;
        }
    }

    public List<String> getAllProcesscardCode(){
        try {
            return processcardRepository
                    .findAll()
                    .stream()
                    .map(Processcard::getProcesscardCode)
                    .distinct()
                    .collect(Collectors.toList());
        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 根据前端的请求体查找对应的库存信息
     * @param parameter 前端的请求体
     * @return 库存列表
     */
    public List<Inventory> getInventoryByParameter(FindInventoryParameter parameter){
        if (parameter.getProcesscardCode()==null){
            List<Inventory> inventories = inventoryRepository.findInventoriesByWorkNumAndInventoryStatus(parameter.getWorkNum(),1);
             return inventories.stream()
                    .filter(inventory -> {
                        String storageCode = storageRepository.findCodeById(inventory.getStorageId());
                        return storageCode != null && storageCode.startsWith(parameter.getZoneCode());
                    })
                    .collect(Collectors.toList());

        } else if (parameter.getWorkNum()==null){
            String processcardCode = parameter.getProcesscardCode();
            if (processcardCode.startsWith("-")) {
                processcardCode = "  ".concat(processcardCode);
            }
//            else {
//                int index = processcardCode.indexOf("-");
//                String afterCut = processcardCode.substring(index);
//                processcardCode = "  ".concat(afterCut);
//            }

            Integer processcardId = processcardRepository.findByProcesscardCode(processcardCode).getId();
            List<Inventory> inventories = inventoryRepository.findInventoriesByProcesscardIdAndInventoryStatus(processcardId,1);
            return inventories.stream()
                    .filter(inventory -> {
                        String storageCode = storageRepository.findCodeById(inventory.getStorageId());
                        return storageCode != null && storageCode.startsWith(parameter.getZoneCode());
                    })
                    .collect(Collectors.toList());
        }else {
            String processcardCode = parameter.getProcesscardCode();
            if (processcardCode.startsWith("-")) {
                processcardCode = "  ".concat(processcardCode);
            }
//            else {
//                int index = processcardCode.indexOf("-");
//                String afterCut = processcardCode.substring(index);
//                processcardCode = "  ".concat(afterCut);
//            }
            Integer processcardId = processcardRepository.findByProcesscardCode(processcardCode).getId();
            List<Inventory> inventories = inventoryRepository.findInventoriesByWorkNumAndProcesscardIdAndInventoryStatus(parameter.getWorkNum(), processcardId,1);
            return inventories.stream()
                    .filter(inventory -> {
                        String storageCode = storageRepository.findCodeById(inventory.getStorageId());
                        return storageCode != null && storageCode.startsWith(parameter.getZoneCode());
                    })
                    .collect(Collectors.toList());
        }
    }

    public void deleteOutBoundOrder(Integer orderId){
        List<OutBoundOrderDetail> details = outBoundOrderDetailRepository.findOutBoundOrderDetailsByOutBoundOrderId(orderId);
        List<Integer> palletIds = details.stream().map(OutBoundOrderDetail::getPalletId).collect(Collectors.toList());
        List<Inventory> inventories  = inventoryRepository.findInventoriesInPalletIds(palletIds);
        List<Integer> storageIds = inventories.stream().map(Inventory::getStorageId).collect(Collectors.toList());

        // 找到出库单对应的储位编码
        List<String> storageCodes = storageIds
                .stream()
                .map(storageRepository::findCodeById)
                .collect(Collectors.toList());

        // 释放储位
        storageCodes.forEach(storageService::openStorage);

        // 恢复库存状态
        inventories.stream()
                .peek(x -> x.setInventoryStatus(1))
                .forEach(inventoryRepository::save);

        // 删除出库单对应的出库任务
        outBoundMissionRepository.deleteOutBoundMissionsByOutBoundOrderId(orderId);

        // 删除出库单对应的出库单明细
        outBoundOrderDetailRepository.deleteOutBoundOrderDetailsByOutBoundOrderId(orderId);

        // 最后删除出库单
        outBoundOrderRepository.deleteOutBoundOrderById(orderId);
    }

    @Transactional
    public boolean chooseFlowTo(Integer orderId, Integer flowTo){
        List<OutBoundOrderDetail> outBoundOrderDetails = outBoundOrderDetailRepository.findOutBoundOrderDetailsByOutBoundOrderId(orderId);
        int result = 0;
        for (OutBoundOrderDetail outBoundOrderDetail : outBoundOrderDetails) {
            Integer palletId = outBoundOrderDetail.getPalletId();
            result = palletRepository.updateFlowToByPalletId(palletId, flowTo)+result;
        }
        return result == outBoundOrderDetails.size();
    }
}
